package org.jflame.web.spring;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.jflame.commons.model.CallResult;
import org.jflame.commons.model.ResultEnum;
import org.jflame.context.spring.SpringContextHolder;
import org.jflame.web.WebUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import jakarta.servlet.http.HttpServletRequest;

public final class SpringWebUtils {

    /**
     * 动态注册controller,注册整个类
     *
     * @param controllerClass
     * @throws Exception
     */
    public static void registerController(Class<?> controllerClass) throws Exception {
        ApplicationContext applicationContext = SpringContextHolder.getSpringContext();
        RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) applicationContext
                .getBean(RequestMappingHandlerMapping.class);
        String beanName = StringUtils.uncapitalize(controllerClass.getSimpleName());
        SpringContextHolder.registerBean(beanName, controllerClass);

        Method method = requestMappingHandlerMapping.getClass()
                .getSuperclass()
                .getSuperclass()
                .getDeclaredMethod("detectHandlerMethods", Object.class);
        method.setAccessible(true);
        method.invoke(requestMappingHandlerMapping, beanName);

    }

    /**
     * 动态注册一个类的方法为请求处理方法.
     *
     * @param controller 类实例
     * @param method 方法名,方法名如果在类中不唯一,只会注册第一个
     * @param requestMappingInfo 请求属性,包括路径,httpMethod等
     */
    public static void addMapping(Object controller, String method, RequestMappingInfo requestMappingInfo) {
        ApplicationContext applicationContext = SpringContextHolder.getSpringContext();
        RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) applicationContext
                .getBean(RequestMappingHandlerMapping.class);
        Method[] methods = controller.getClass()
                .getMethods();
        for (Method m : methods) {
            if (m.getName()
                    .equals(method)) {
                requestMappingHandlerMapping.registerMapping(requestMappingInfo, controller, m);
                return;
            }
        }
    }

    /**
     * 动态注册一个类的方法为请求处理方法,支持get,post两种方式.
     *
     * @param controller 类实例
     * @param method 方法名,方法名如果在类中不唯一,只会注册第一个
     * @param path 请求地址
     */
    public static void addMapping(Object controller, String method, String path) {
        RequestMappingInfo mappingInfo = RequestMappingInfo.paths(path)
                .methods(RequestMethod.GET, RequestMethod.POST)
                .build();
        addMapping(controller, method, mappingInfo);
    }

    /**
     * 接口是否需要返回json数据.判断条件:<br>
     * 1.如果是accept是json,或带有x-requested-with的请求头 <br>
     * 2.contoller方法有ResponseBody注解和类上有RestController注解
     *
     * @param request HttpServletRequest
     * @param handler handler
     * @return
     */
    public static boolean isJsonResult(HttpServletRequest request, Object handler) {
        if (handler instanceof HandlerMethod handlerMethod) {
            if (handlerMethod.hasMethodAnnotation(ResponseBody.class) || handlerMethod.getBeanType()
                    .isAnnotationPresent(RestController.class)
                    || handlerMethod.getBeanType()
                            .isAnnotationPresent(ResponseBody.class)) {
                return true;
            }
        }
        if (WebUtils.isJsonRequest(request) || WebUtils.isAjaxRequest(request)) {
            return true;
        }
        return false;
    }

    /**
     * 将errors对象转换为CallResult输出,验证错误转为map
     *
     * @param error 错误对象
     * @see org.springframework.validation.Errors
     */
    public static CallResult<Map<String,String>> convertError(Errors error) {
        CallResult<Map<String,String>> result = new CallResult<>();
        if (error.hasErrors()) {
            result.setStatus(ResultEnum.PARAM_ERROR.getStatus());
            Map<String,String> errMap = new HashMap<>();
            String errorMsg = "";
            if (error.hasGlobalErrors()) {
                String globalMsg = "";
                for (ObjectError ferr : error.getGlobalErrors()) {
                    globalMsg = globalMsg + ferr.getDefaultMessage() + ";";
                }
                errorMsg += globalMsg;
                errMap.put("_global_msg", globalMsg);
            }
            if (error.hasFieldErrors()) {
                for (FieldError ferr : error.getFieldErrors()) {
                    errMap.put(ferr.getField(), ferr.getDefaultMessage());
                    errorMsg = errorMsg + ferr.getDefaultMessage() + ";";
                }
            }
            result.setMessage(errorMsg);
            result.setData(errMap);
        }
        return result;
    }

    /**
     * 返回当前请求上下文的HttpServletRequest(需要配置springweb的RequestContextListener实现)
     *
     * @return RequestContextListener
     */
    public static HttpServletRequest getRequest() {
        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (sra != null) {
            return sra.getRequest();
        }
        return null;
    }

    /*public CallResult<Object> getAllUr() throws Exception {
        RequestMappingHandlerMapping mapping = SpringContextHolder.getBean(RequestMappingHandlerMapping.class);
        Map<RequestMappingInfo,HandlerMethod> map = mapping.getHandlerMethods();
    
        List<List<String>> sheetData = new ArrayList<>();
    
        Set<RequestMappingInfo> requestMappingInfos = map.keySet();
        for (RequestMappingInfo requestMappingInfo : requestMappingInfos) {
            List<String> rowData = new ArrayList<>();
            System.out.println(requestMappingInfo.getPatternsCondition());
            System.out.println("==" + requestMappingInfo.getMethodsCondition()
                    .toString());
    
            // beanName
            HandlerMethod handlerMethod = map.get(requestMappingInfo);
            rowData.add(handlerMethod.getBean()
                    .toString());
    
            // 全路径
            String fullClassPath = handlerMethod.getBeanType()
                    .getName();
            rowData.add(fullClassPath);
            PatternsRequestCondition prc = requestMappingInfo.getPatternsCondition();
            if (prc != null) {
                // 请求地址
                Set<String> patterns = prc.getPatterns();
                for (String url : patterns) {
                    rowData.add(url + " ");
                }
            }
    
            // 请求方式
            Set<RequestMethod> requestMethods = requestMappingInfo.getMethodsCondition()
                    .getMethods();
            for (RequestMethod requestMethod : requestMethods) {
                rowData.add(requestMethod.name() + " ");
            }
    
            sheetData.add(rowData);
        }
        return CallResult.success(sheetData);
    }*/
}
